package me.itblog.mvc.modules.front;

import com.redfin.sitemapgenerator.ChangeFreq;
import com.redfin.sitemapgenerator.WebSitemapGenerator;
import com.redfin.sitemapgenerator.WebSitemapUrl;
import me.itblog.bean.Article;
import me.itblog.bean.AuthorProfile;
import me.itblog.bean.LuceneSearchResult;
import me.itblog.services.ArticleLuceneService;
import me.itblog.services.CacheManager;
import me.itblog.services.MenuService;
import me.itblog.utils.Constant;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.QueryResult;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.OrderBy;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Maths;
import org.nutz.lang.Strings;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Fail;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.view.ForwardView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.MalformedURLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2015/10/9.
 */
@IocBean(create = "init")
public class IndexModule {

    private Logger logger = LoggerFactory.getLogger(IndexModule.class);

    Map<String, Map<String, Object>> menuMap = new HashMap<>();

    public void init() {
        List<Map<String, Object>> menuList = MenuService.me().getMenuList();
        menuList.forEach((menuItem) -> {
            String link = menuItem.get("link").toString();
            menuMap.put(link, menuItem);
        });
    }

    @Inject
    Dao dao;

    @Inject
    CacheManager cacheManager;

    @Inject
    ArticleLuceneService articleLuceneService;

    @Inject("refer:conf")
    PropertiesProxy conf;

    @Inject("java:$conf.get('seo.urlbase')")
    protected String urlbase;

    /**
     * 网站title
     */
    @Inject("java:$conf.get('seo.title')")
    protected String title;


    /**
     * 主页显示，默认按照T(time)翻页
     *
     * @param page
     * @return
     * @throws Exception
     */
    @At({"/", "/index", "/l", "/l/t/", "/l/t", "/l/t/?"})
    @Fail(">>:/l")
    @Ok("beetl:/index.btl")
    public Map<String, Object> listBlog(int page) throws Exception {
        logger.info("IndexModule >>> listBlog");
        /// hot category
        List<Map> list = cacheManager.getHotCategory();

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageType", "/l/t/");

        params.put("fiveList", cacheManager.getHotArticle());
        params.put("leftListType", "热门推荐");

        params.put("hotCategory", list);
        params.put("title", "itblog.me-" + title);
        params.put("result", cacheManager.getNewArticle(page));
        return params;
    }



    private void randomLeftArticle(Map<String, Object> params) {
        if (Math.random() * 10 < 6) {
            params.put("fiveList", cacheManager.getHotArticle());
            params.put("leftListType", "热门推荐");
        } else {
            params.put("fiveList", cacheManager.getLeftNewArticle());
            params.put("leftListType", "最新推荐");
        }
    }

    /**
     * 按照目录显示
     *
     * @param id
     * @param page
     * @return
     * @throws Exception
     */
    @At({"/l/c/?", "/l/c/?/?"})
    @Fail(">>:/l")
    @Ok("beetl:/index.btl")
    public Map<String, Object> listOld(String id, int page) throws Exception {
        logger.info("IndexModule >>> listOld");

        int currPage = page > 0 ? page : 1;
        int pageSize = Constant.list_page_size;

        Entity<Article> entity = dao.getEntity(Article.class);
        Sql sql = Sqls.create("SELECT ar.* FROM `t_article` ar , t_article_category ac where ac.article_id = ar.id and ac.category_id = @id LIMIT @offsize , @pagesize");
        sql.setCallback(Sqls.callback.entities()).setEntity(entity)
                .params().set("id", id).set("offsize", (currPage - 1) * pageSize).set("pagesize", pageSize);
        dao.execute(sql);
        List<Article> articleList = sql.getList(Article.class);


        Pager pager = dao.createPager(currPage, pageSize);
        if (articleList.size() > 0) {
            pager.setRecordCount(cacheManager.getCategoryCount(id));
        } else {
            pager.setRecordCount(0);
        }

        /// hot category
        List<Map> list = cacheManager.getHotCategory();

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageType", "/l/c/" + id + "/");

        randomLeftArticle(params);

        params.put("hotCategory", list);
        params.put("title", "itblog.me-" + title);
        params.put("result", new QueryResult(articleList, pager));
        return params;
    }


    /**
     * 按照目录显示
     *
     * @param id
     * @param categoryName
     * @param page
     * @return
     * @throws Exception
     */
    @At({"/l/c/?/?", "/l/c/?/?/?"})
    @Fail(">>:/l")
    @Ok("beetl:/index.btl")
    public Map<String, Object> listc(String id,String categoryName, int page) throws Exception {
        logger.info("IndexModule >>> listc");

        int currPage = page > 0 ? page : 1;
        int pageSize = Constant.list_page_size;

        Entity<Article> entity = dao.getEntity(Article.class);
        Sql sql = Sqls.create("SELECT ar.* FROM `t_article` ar , t_article_category ac where ac.article_id = ar.id and ac.category_id = @id LIMIT @offsize , @pagesize");
        sql.setCallback(Sqls.callback.entities()).setEntity(entity)
                .params().set("id", id).set("offsize", (currPage - 1) * pageSize).set("pagesize", pageSize);
        dao.execute(sql);
        List<Article> articleList = sql.getList(Article.class);


        Pager pager = dao.createPager(currPage, pageSize);
        if (articleList.size() > 0) {
            pager.setRecordCount(cacheManager.getCategoryCount(id));
        } else {
            pager.setRecordCount(0);
        }

        /// hot category
        List<Map> list = cacheManager.getHotCategory();

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageType", "/l/c/" + id + "/" + categoryName + "/");

        randomLeftArticle(params);

        params.put("hotCategory", list);
        params.put("title", categoryName+"-" + title);
        params.put("result", new QueryResult(articleList, pager));
        return params;
    }


    /**
     * 菜单
     *
     * @param id
     * @param page
     * @return
     * @throws Exception
     */
    @At({"/l/m/?", "/l/m/?/?"})
    @Ok("beetl:/index.btl")
    @Fail(">>:/l")
    public Map<String, Object> menu(String id, int page) throws Exception {
        logger.info("IndexModule >>> menu");

        Map<String, Object> stringObjectMap = menuMap.get(id);
        if (stringObjectMap == null) {
            throw Lang.impossible();
        }

        int currPage = page > 0 ? page : 1;
        int pageSize = Constant.list_page_size;

        Entity<Article> entity = dao.getEntity(Article.class);
        Sql sql = Sqls.create("SELECT DISTINCT  ar.* FROM `t_article` ar , t_article_category ac $cnd");

        OrderBy orderBy = Cnd.where("category_id", "in", stringObjectMap.get("tagIds"))
                .and(new Static("ac.article_id = ar.id order by create_time desc limit " + (currPage - 1) * pageSize + " ," + pageSize));

        sql.setCallback(Sqls.callback.entities()).setEntity(entity);
        sql.setVar("cnd", orderBy);
        dao.execute(sql);
        List<Article> articleList = sql.getList(Article.class);

        Pager pager = dao.createPager(currPage, pageSize);
        if (articleList.size() > 0) {
            Sql countSql = Sqls.create("SELECT count(DISTINCT ar.id ) cnt FROM `t_article` ar , t_article_category ac  $cnd");
            countSql.setCallback(Sqls.callback.entities()).setEntity(entity);
            countSql.setVar("cnd", Cnd.where("category_id", "in", stringObjectMap.get("tagIds")).and(new Static("ac.article_id = ar.id")));
            pager.setRecordCount(cacheManager.getCount(countSql));
        } else {
            pager.setRecordCount(0);
        }

        /// hot category
        List<Map> list = cacheManager.getHotCategory();

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageType", "/l/m/" + id + "/");

        randomLeftArticle(params);

        params.put("hotCategory", list);
        params.put("title", stringObjectMap.get("title") + "-" + title);
        params.put("result", new QueryResult(articleList, pager));
        return params;
    }


    /**
     * 按照作者分类
     *
     * @param id
     * @param page
     * @return
     * @throws Exception
     */
    @At({"/l/a/?", "/l/a/?/?"})
    @Ok("beetl:/author.html")
    public Map<String, Object> author(String id, int page) throws Exception {
        logger.info("IndexModule >>> author");
        AuthorProfile authorProfile = dao.fetch(AuthorProfile.class, Cnd.where("id", "=", id));

        Pager pager = dao.createPager(page > 0 ? page : 1, Constant.list_page_size);
        List<Article> articleList = dao.query(Article.class, Cnd.where("authorId", "=", id).desc("create_time"), pager);

        if (authorProfile != null) {
            pager.setRecordCount(cacheManager.getAuthorCount(id));
        } else {
            pager.setRecordCount(0);
        }

        Map<String, Object> params = new HashMap<String, Object>();

        /// hot category
        List<Map> hotCategory = cacheManager.getHotCategory();
        params.put("pageType", "/l/a/" + id + "/");
        params.put("fiveList", cacheManager.getHotArticle());
        params.put("leftListType", "热门推荐");
        params.put("author", authorProfile);
        params.put("hotCategory", hotCategory);
        params.put("title", authorProfile.getName() + "-" + title);
        params.put("result", new QueryResult(articleList, pager));
        return params;
    }

    /**
     * 单个文章显示
     *
     * @param id
     * @return
     * @throws Exception
     */
    @At("/a/?")
    @Ok("beetl:/blog.html")
    @Fail(">>:/l")
    public Map<String, Object> blog(String id) throws Exception {
        logger.info("IndexModule >>> blog");

        Article article = dao.fetch(Article.class, Cnd.where("id", "=", id));
        if (article != null) {
            dao.fetchLinks(article, "author");
            article.setViews(article.getViews() + 1);
            dao.update(article, "views|updateTime");
            cacheManager.updateArticleStats(article);
            Map<String, Object> params = new HashMap<String, Object>();
            /// hot category
            List<Map> hotCategory = cacheManager.getHotCategory();
            params.put("article", article);
            params.put("author", article.getAuthor());
            //相关推荐
            List<Article> xiangGuanArtivcles = getXiangGuanArtivcles(id);
            if (xiangGuanArtivcles.isEmpty()) {
                Pager pager = dao.createPager(1, Constant.left_list_page_size);
                xiangGuanArtivcles = dao.query(Article.class, Cnd.where("authorId", "=", article.getAuthorId()).desc("views"), pager);
            }
            params.put("fiveList", xiangGuanArtivcles);
            params.put("leftListType", "相关推荐");
            params.put("hotCategory", hotCategory);
            params.put("title", article.getTitle() + "-" + title);
            return params;
        } else {
            return null;
        }
    }


    @At("/search")
    @Ok("beetl:/serach.html")
    @Fail(">>:/l")
    public Object search(@Param("q") String keys) throws Exception {
        logger.info("IndexModule >>> search");
        if (Strings.isBlank(keys))
            return new ForwardView("/");
        List<LuceneSearchResult> results = articleLuceneService.search(keys, true, Constant.search_list_page_size);
//        List<Article> list = new ArrayList();
//        for (LuceneSearchResult result : results) {
//            Article topic = dao.fetch(Article.class, result.getId());
//            if (topic == null)
//                continue;
//            topic.setTitle(result.getResult());
//            list.add(topic);
//        }
        Pager pager = dao.createPager(1, Constant.search_list_page_size);
        pager.setRecordCount(results.size());

        /// hot category
        List<Map> hotCategoryList = cacheManager.getHotCategory();

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pageType", "/l/t/");

        params.put("fiveList", cacheManager.getHotArticle());
        params.put("leftListType", "热门推荐");

        params.put("hotCategory", hotCategoryList);
        params.put("title", keys + title);
        params.put("result",  new QueryResult(results, pager));
        return params;
    }
    /**
     * 获取相关博客
     *
     * @param article_id
     * @return
     */
    private List<Article> getXiangGuanArtivcles(String article_id) {
        String sqlString = "SELECT DISTINCT t.* from t_article t,t_article_category ta where t.id = ta.article_id and ta.category_id in ( " +
                "SELECT tt.category_id from t_article_category tt where tt.article_id = @id " +
                ") and t.id != @id ORDER BY t.views desc LIMIT 0, @limitcount";
        Entity<Article> entity = dao.getEntity(Article.class);
        Sql sql = Sqls.fetchEntity(sqlString);
        sql.params().set("id", article_id);
        sql.params().set("limitcount", Constant.left_list_page_size);
        sql.setCallback(Sqls.callback.entities()).setEntity(entity);
        dao.execute(sql);
        return sql.getList(Article.class);
    }


    @At("/go/?")
    @Ok("redirect:${obj}")
    public String go(String id) throws Exception {
        logger.info("IndexModule >>> go");
        Article article = dao.fetch(Article.class, Cnd.where("id", "=", id));
        if (article != null) {
            article.setViews(article.getViews() + 1);
            dao.update(article, "views|updateTime");
            cacheManager.updateArticleStats(article);
            return article.getLink();
        } else {
            return "/l";
        }
    }


    /**
     * 输出Sitemap
     */
    @At({"/sitemap","/sitemap.txt","/sitemap.xml"})
    @Ok("raw:xml")
    public File sitemap() throws MalformedURLException, ParseException {
        String tmpdir = conf.get("seo.tmp_dir", "/tmp");
        Files.createDirIfNoExists(tmpdir);
        final WebSitemapGenerator gen = new WebSitemapGenerator(urlbase, new File(tmpdir));
        gen.addUrl(urlbase + "/l/");

        Entity<Article> entity = dao.getEntity(Article.class);
        Sql sql = Sqls.fetchEntity("select ta.id,ta.create_time from t_article ta where ta.contents is not null ORDER BY ta.create_time desc LIMIT 1000");
        sql.setCallback(Sqls.callback.entities()).setEntity(entity);
        dao.execute(sql);
        List<Article> articleList = sql.getList(Article.class);
        for (Article article : articleList) {
            try {
                WebSitemapUrl.Options options = new WebSitemapUrl.Options(urlbase + "/a/" + article.getId());
                options.lastMod(new Date(article.getCreateTime()));
                options.priority(1D);
                options.changeFreq(ChangeFreq.DAILY);
                WebSitemapUrl url = new WebSitemapUrl(options);
                gen.addUrl(url);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        List<File> list = gen.write();
        if (list.size() > 0)
            return list.get(0);
        return null;
    }

    @At("/version")
    @Ok("beetl:/version.btl")
    public Map<String, Object> version() throws Exception {
        logger.info("IndexModule >>> version");
        Map<String, Object> params = Constant.getVersionMap();
        params.put("title", "itblog.me-" + title);
        return params;
    }
}
